use diesel::prelude::*;
use diesel::PgConnection;

use crate::models::{
  person::{NewPerson, Person},
  person_role::NewPersonRole,
  role::NewRole,
};

use crate::schema::{persons, persons_roles};

use super::role::RoleMapper;

pub struct PersonMapper;

impl PersonMapper {
  pub fn create(
    conn: &mut PgConnection,
    new_person: NewPerson,
    role_codes: Vec<String>,
  ) -> QueryResult<Person> {
    let person = diesel::insert_into(persons::table)
      .values(new_person)
      .get_result::<Person>(conn)?;

    for role_code in role_codes {
      let new_person_role = {
        if let Ok(role) = RoleMapper::find_by_code(conn, &role_code) {
          NewPersonRole {
            person_id: person.id,
            role_id: role.id,
          }
        } else {
          let new_role = NewRole {
            code: role_code.to_owned(),
            name: role_code,
          };
          let role = RoleMapper::create(conn, new_role)?;

          NewPersonRole {
            person_id: person.id,
            role_id: role.id,
          }
        }
      };
      diesel::insert_into(persons_roles::table)
        .values(new_person_role)
        .execute(conn)?;
    }

    Ok(person)
  }
}
